#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "iot_gpio.h"
#include "hi_io.h"
#include "iot_gpio.h"
#include <sys/time.h>
#include <sys/types.h>
#include <stddef.h>
#include "net_demo.h"
#include "net_common.h"

#include "light_control.h"
#include "sg92.h"
#include "PIR.h"

#define RED_GPIO_10 10
#define GREEN_GPIO_11 11
#define BLUE_GPIO_12 12

#define PWM_PORT_NUM1 (1)
#define PWM_PORT_NUM2 (2)
#define PWM_PORT_NUM3 (3)

#define PIR_GPIO_7 7
#define YELLOW_LED_GPIO_8 8

#define IOT_IO_NAME_GPIO_2 2 // 舵机控制引脚
// 红灯和绿色表示工作状态
#define RED_GPIO_0 0
#define GREEN_GPIO_1 1

#define GPIO_HIGH (1)
#define GPIO_LOW (0)

static char request[] = "choice: door light";
// static char door_request[] = "choice: open close break";
// static char light_request[] = "choice: red green blue close break";
// static char PIR_request[128] = "choice:PIRopen PIRclose";
static char response[128] = "";
static char light_intensity[128] = "";
// static int result;
static int intensity;

#define DELAY_1S (1)

void TcpServerTest(unsigned short port)
{
    ssize_t retval = 0;
    int backlog = 1;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
    int connfd = -1;

    struct sockaddr_in clientAddr = {0};
    socklen_t clientAddrLen = sizeof(clientAddr);
    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);              // 端口号，从主机字节序转为网络字节序
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 允许任意主机接入， 0.0.0.0

    retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); // 绑定端口
    if (retval < 0)
    {
        printf("bind failed, %ld!\r\n", retval);
        close(sockfd);
    }
    printf("bind to port %hu success!\r\n", port);

    retval = listen(sockfd, backlog); // 开始监听
    if (retval < 0)
    {
        printf("listen failed!\r\n");
        close(sockfd);
    }
    printf("listen with %d backlog success!\r\n", backlog);

    // 接受客户端连接，成功会返回一个表示连接的 socket ， clientAddr 参数将会携带客户端主机和端口信息 ；失败返回 -1
    // 此后的 收、发 都在 表示连接的 socket 上进行；之后 sockfd 依然可以继续接受其他客户端的连接，
    //  UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接，父进程继续接受其他客户端的连接
    //  鸿蒙liteos-a内核之上，可以使用UNIX的“每个连接一个进程”的并发模型
    //     liteos-m内核之上，可以使用“每个连接一个线程”的并发模型
    connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
    if (connfd < 0)
    {
        printf("accept failed, %d, %d\r\n", connfd, errno);
        close(sockfd);
    }
    printf("accept success, connfd = %d!\r\n", connfd);
    printf("client addr info: host = %s, port = %hu\r\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));

    while (1)
    {
        // 建立连接成功之后，这个TCP socket描述符 —— sockfd 就具有了 “连接状态”，
        // 发送、接收 对端都是 connect 参数指定的目标主机和端口
        retval = send(connfd, request, strlen(request), 0);
        if (retval < 0)
        {
            printf("send request failed!\r\n");
        }
        printf("send request{%s} %ld to server done!\r\n", request, retval);

        retval = recv(connfd, response, sizeof(response), 0);
        if (retval <= 0)
        {
            printf("send response from server failed or done, %ld!\r\n", retval);
        }
        response[retval] = '\0';
        printf("recv response{%s} %ld from server done!\r\n", response);

        // 门
        if (strcmp(response, "door") == 0)
        {
            printf("door!\r\n");
            while (1)
            {
                static int state;
                memset(response, 0, sizeof(response));
                recv(connfd, response, sizeof(response), 0);
                printf("recv response{%s} %ld from server done!\r\n", response);
                if (strcmp(response, "open") == 0)
                {
                    if (state == 1)
                    {
                        send(connfd, "The door is already open!\r\n", sizeof("The door is already open!"), 0);
                        printf("The door is already open!\r\n");
                        memset(response, 0, sizeof(response));
                        continue;
                    }
                    else
                    {
                        printf("The door is opening!\r\n");
                        state = OpenTask(sockfd);
                    }
                }
                else if (strcmp(response, "close") == 0)
                {
                    if (state == 0)
                    {
                        send(connfd, "The door is already closed!\r\n", sizeof("The door is already closed!"), 0);
                        printf("The door is already closed!\r\n");
                        memset(response, 0, sizeof(response));
                        continue;
                    }
                    else
                    {
                        printf("The door is closing!\r\n");
                        state = CloseTask(sockfd);
                    }
                }
                else if (strcmp(response, "monitor") == 0)
                {
                    printf("monitor!\r\n");

                    fd_set read_fds;
                    struct timeval timeout;
                    int max_fd = connfd; // 假设connfd是你想要监视的文件描述符
                    char buffer[100];
                    memset(buffer, 0, sizeof(buffer));

                    while (1)
                    {
                        FD_ZERO(&read_fds);
                        FD_SET(connfd, &read_fds); // 将网络连接的文件描述符添加到要监视的集合中

                        // 设置超时时间，这里设置为1秒，可根据实际情况调整
                        timeout.tv_sec = 1;
                        timeout.tv_usec = 0;

                        // 调用select函数进行监视，等待connfd有可读数据或者超时
                        int ret = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);

                        if (ret == -1)
                        {
                            perror("select error");
                            return 1;
                        }
                        else if (ret == 0)
                        {
                            // 超时情况，继续执行正常的循环任务
                            PIRTask(connfd);
                        }
                        else
                        {
                            // 当select返回且connfd可读时，说明有输入了，去获取输入内容并判断
                            if (FD_ISSET(connfd, &read_fds))
                            {
                                // 使用recv获取输入内容
                                ssize_t bytes_received = recv(connfd, buffer, sizeof(buffer) - 1, 0);
                                if (bytes_received <= 0)
                                {
                                    // 连接关闭或错误
                                    break;
                                }

                                // 确保字符串以null结尾
                                buffer[bytes_received] = '\0';

                                // 去除字符串末尾的换行符（如果有的话）
                                if (buffer[strlen(buffer) - 1] == '\n')
                                {
                                    buffer[strlen(buffer) - 1] = '\0';
                                }
                                // 检查接收到的命令
                                if (strcmp(buffer, "monitor close") == 0)
                                {
                                    printf("monitor close!\r\n");
                                    PIRTask(-1);
                                    break;
                                }
                            }
                        }
                    }
                }
                else if (strcmp(response, "break") == 0)
                {
                    printf("door break!\r\n");
                    memset(response, 0, sizeof(response));
                    break;
                }
            }
        }
        // 灯
        else if (strcmp(response, "light") == 0)
        {
            while (1)
            {
                memset(response, 0, sizeof(response));
                static int sta;
                recv(connfd, response, sizeof(response), 0);
                printf("recv response{%s} %ld from server done!\r\n", response);
                if (strcmp(response, "red") == 0)
                {
                    printf("recv response{%s} %ld from server done!\r\n", response);
                    while (1)
                    {
                        memset(light_intensity, 0, sizeof(light_intensity));
                        recv(connfd, light_intensity, sizeof(light_intensity), 0);
                        printf("recv light_intensity{%s} %ld from server done!\r\n", response);
                        if (strcmp(light_intensity, "close") == 0)
                        {
                            printf("red close!\r\n");
                            light_close(sta);
                            break;
                        }
                        else
                        {
                            intensity = atoi(light_intensity);
                            sta = redTask(intensity);
                            printf("intensity = %d\r\n", intensity);
                        }
                    }
                    memset(response, 0, sizeof(response));
                }
                else if (strcmp(response, "green") == 0)
                {
                    printf("green light!\r\n");
                    while (1)
                    {

                        memset(light_intensity, 0, sizeof(light_intensity));
                        recv(connfd, light_intensity, sizeof(light_intensity), 0);
                        printf("recv light_intensity{%s} %ld from server done!\r\n", response);
                        sta = greenTask(intensity);

                        if (strcmp(light_intensity, "close") == 0)
                        {
                            printf("green close!\r\n");
                            light_close(sta);
                            break;
                        }
                        else
                        {
                            intensity = atoi(light_intensity);
                            printf("intensity = %d\r\n", intensity);
                            sta = greenTask(intensity);
                        }
                    }
                    memset(response, 0, sizeof(response));
                }
                else if (strcmp(response, "blue") == 0)
                {
                    printf("blue light!\r\n");
                    while (1)
                    {
                        memset(light_intensity, 0, sizeof(light_intensity));
                        recv(connfd, light_intensity, sizeof(light_intensity), 0);
                        printf("recv light_intensity{%s} %ld from server done!\r\n", response);
                        printf("%s", light_intensity);
                        if (strcmp(light_intensity, "close") == 0)
                        {
                            light_close(sta);
                            break;
                        }
                        else
                        {
                            intensity = atoi(light_intensity);
                            printf("intensity = %d\r\n", intensity);
                            sta = blueTask(intensity);
                        }
                    }
                    memset(response, 0, sizeof(response));
                }
                else if (strcmp(response, "white") == 0)
                {
                    printf("white light!\r\n");
                    while (1)
                    {
                        memset(light_intensity, 0, sizeof(light_intensity));
                        recv(connfd, light_intensity, sizeof(light_intensity), 0);
                        printf("recv light_intensity{%s} %ld from server done!\r\n", response);
                        if (strcmp(light_intensity, "close") == 0)
                        {
                            printf("white close!\r\n");
                            light_close(sta);
                            break;
                        }
                        else
                        {
                            intensity = atoi(light_intensity);
                            printf("intensity = %d\r\n", intensity);
                            sta = whiteTask(intensity);
                        }
                    }
                    memset(response, 0, sizeof(response));
                }
                else if (strcmp(response, "break") == 0)
                {
                    printf("ligth break!\r\n");
                    memset(response, 0, sizeof(response));
                    break;
                }
            }
        }

        memset(response, 0, sizeof(response));
    }
}

void SmartHomeTask(void)
{
    hi_gpio_init();
    // Light
    IoTGpioSetDir(RED_GPIO_10, IOT_GPIO_DIR_OUT);
    IoTGpioSetDir(GREEN_GPIO_11, IOT_GPIO_DIR_OUT);
    IoTGpioSetDir(BLUE_GPIO_12, IOT_GPIO_DIR_OUT);
    hi_io_set_func(RED_GPIO_10, HI_IO_FUNC_GPIO_10_PWM1_OUT);
    hi_io_set_func(GREEN_GPIO_11, HI_IO_FUNC_GPIO_11_PWM2_OUT);
    hi_io_set_func(BLUE_GPIO_12, HI_IO_FUNC_GPIO_12_PWM3_OUT);
    IoTPwmInit(PWM_PORT_NUM1);
    IoTPwmInit(PWM_PORT_NUM2);
    IoTPwmInit(PWM_PORT_NUM3);
    // PIR
    IoTGpioSetDir(YELLOW_LED_GPIO_8, IOT_GPIO_DIR_OUT);
    IoTGpioSetDir(PIR_GPIO_7, IOT_GPIO_DIR_IN);
    // 门
    hi_io_set_func(IOT_IO_NAME_GPIO_2, HI_IO_FUNC_GPIO_2_GPIO);
    hi_io_set_func(GREEN_GPIO_1, 0);
    hi_io_set_func(RED_GPIO_0, 0);
    IoTGpioSetDir(IOT_IO_NAME_GPIO_2, IOT_GPIO_DIR_OUT);
    IoTGpioSetDir(RED_GPIO_0, IOT_GPIO_DIR_OUT);
    IoTGpioSetDir(GREEN_GPIO_1, IOT_GPIO_DIR_OUT);
}

SYS_RUN(SmartHomeTask);

SERVER_TEST_DEMO(TcpServerTest);